Over-the-Air NVIDIA Jetson - RAUC Advanced Topics and Troubleshooting
RAUC on NVIDIA Jetson: Advanced Topics and Troubleshooting
This page documents advanced integration topics and the main issues encountered during bring-up and A/B update validation.
It covers:
- Adaptive updates
- Persistent state design
- Common bundle, service, and bootloader failures
- Custom backend failure modes
- Practical troubleshooting notes
Enabling RAUC Adaptive Updates
After validating the signed A/B update flow, the next step was to prepare the integration for adaptive updates.
The purpose of this change was to make RAUC reuse persistent update metadata across both rootfs slots, reducing unnecessary data transfer and aligning the design with a production-ready A/B layout.
What Had to Change
The adaptive update path required three essential changes:
- use verity bundles instead of plain
- enable adaptive=block-hash-index for the rootfs image
- move RAUC runtime state to a shared persistent location
In practice, this meant updating both the bundle recipe and the RAUC runtime configuration.
Bundle Recipe Changes
The original bundle recipe still used:
RAUC_BUNDLE_FORMAT = "plain"
This was updated to:
RAUC_BUNDLE_FORMAT = "verity" RAUC_SLOT_rootfs[adaptive] = "block-hash-index"
These two lines are the key Yocto-side changes that make the bundle adaptive-ready.
Persistent State Requirement
The initial configuration stored RAUC status under:
statusfile=/var/lib/rauc/status
That worked for the basic integration, but it was not suitable for adaptive updates because /var/lib/rauc belongs to the currently booted rootfs.
To solve this, the configuration was changed to:
statusfile=/data/rauc/status data-directory=/data/rauc
This ensures that RAUC state is shared across slot A and slot B.
Backend Alignment
The custom Jetson bootloader backend was also originally using /var/lib/rauc.
To keep the system consistent, its internal state directory was moved to:
/data/rauc
This keeps:
- RAUC status
- backend state
- slot metadata
in the same persistent location.
Persistent /data Mount
A shared state directory only works if it is actually backed by persistent storage.
For that reason, a dedicated mount unit was added so that the Jetson persistent partition (UDA) is mounted on:
/data
Without this step, /data/rauc could still be created inside the rootfs, defeating the purpose of adaptive state sharing.
Main Problems Encountered
Error: Nothing PROVIDES 'demo-bundle'
Cause:
The recipe was not in a layer path that BitBake was parsing.
Fix:
Ensure directory structure matches the layer's BBFILES expectations.
Error: signature verification failed
Cause:
Target CA did not match the signing CA.
Fix:
Rebuild the image including the correct ca.cert.pem and reflash.
Error: RAUC service not starting
Common causes:
- Missing bootloader=
- Invalid bootloader backend
- Missing /var/lib/rauc
- Missing kernel cmdline parameters
Resolved by:
- Setting bootloader=noop initially
- Adding root= and rauc.slot= to cmdline
- Creating the status directory
Error: unsupported custom backend commands
Cause:
The first version of the backend only implemented:
- get-primary
- set-primary
- get-booted
But RAUC also requires:
- get-state
- set-state
Fix:
Extend the backend to implement slot state persistence.
Error: boot status remains bad
Cause:
The backend either:
- did not implement get-state / set-state, or
- always returned bad
Fix:
Persist slot state under backend-managed files and expose them correctly through the custom backend interface.
Error: target still uses RAUC Test CA
Cause:
The image still installed the default example CA rather than the project-generated CA.
Fix:
Copy the generated CA into:
layers/meta-tegrademo/recipes-core/rauc/rauc-conf/files/ca.cert.pem
Then rebuild and reflash.
Error: cmdline and mounted root do not match
Cause:
rauc.slot= may indicate one slot while root= or the actual mounted / still points to another.
Fix:
Always verify:
findmnt -n -o SOURCE / cat /proc/cmdline
The active root device and slot identifier must be consistent.
Practical Debugging Commands
Service and Logs
systemctl status rauc.service --no-pager -l journalctl -xeu rauc.service --no-pager
Slot Validation
rauc status rauc status --output-format=json-pretty
Cmdline Validation
cat /proc/cmdline | tr ' ' '\n' | egrep '^(root=|rauc\.slot=)' findmnt -n -o SOURCE /
Certificate Validation
openssl x509 -in /etc/rauc/ca.cert.pem -noout -subject -issuer -fingerprint -sha256
Backend Validation
/usr/lib/rauc/backend/jetson-extlinux get-primary /usr/lib/rauc/backend/jetson-extlinux get-booted /usr/lib/rauc/backend/jetson-extlinux get-state A /usr/lib/rauc/backend/jetson-extlinux get-state B
Current Limitations
Even with the custom backend, the integration remains relatively simple compared to full bootloader-native A/B systems.
Current limitations include:
- extlinux-based slot control rather than native Jetson boot slot handling
- no automatic rollback policy beyond what is manually implemented
- state persistence relies on the backend implementation
- adaptive update support requires a persistent shared data partition